package com.jetpack.mvvm.lib.binding.viewbind

import android.app.Activity
import android.os.Build
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.activity.ComponentActivity
import androidx.viewbinding.ViewBinding
import com.jetpack.mvvm.lib.binding.ext.*
import java.lang.reflect.Method
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

class ViewGroupViewBinding<T: ViewBinding>(
    clazz: Class<T>,
    private val inflater: LayoutInflater,
    private val viewGroup: ViewGroup ?= null,
    private val isMerge: Boolean = true,
    private val attachedParent: Boolean = true
) : ReadOnlyProperty<ViewGroup, T>{
    private var viewBinding: T? = null
    private var layoutInflater: Method

    init {
        layoutInflater = if (viewGroup != null) {
            if (isMerge) {
                clazz.inflateMethodWithViewGroupWithMerge()
            } else {
                clazz.inflateMethodWithViewGroup()
            }
        } else {
            clazz.inflateMethod()
        }

        viewGroup?.apply {
            when (context) {
                is ComponentActivity -> {
                    (context as ComponentActivity).lifecycle.observerWhenDestroyed { destroyed() }
                }
                is Activity -> {
                    val activity = context as Activity
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                        activity.observerWhenDestroyed { destroyed() }
                    } else {
                        activity.registerLifecycleBelowQ { destroyed() }
                    }
                }
            }
            // 在 init 阶段就绑定自定义 view
            bindView()
        }
    }

    private fun destroyed() {
        viewBinding = null
    }

    override fun getValue(thisRef: ViewGroup, property: KProperty<*>): T {
        return viewBinding?.run {
            this
        } ?: bindView()
    }

    private fun bindView(): T {
        val bind: T = if (viewGroup != null) {
            if (isMerge) {
                layoutInflater.invoke(null, inflater, viewGroup) as T
            } else {
                layoutInflater.invoke(null, inflater, viewGroup, attachedParent) as T
            }
        } else {
            layoutInflater.invoke(null, inflater) as T
        }
        return bind.apply {
            viewBinding = this
        }
    }
}